package com.time.admin.domain.service.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.time.admin.common.entity.PageResult;
import com.time.admin.common.enums.IsDeletedFlagEnum;
import com.time.admin.domain.constants.ExceptionCode;
import com.time.admin.domain.converter.CategoryBOConverter;
import com.time.admin.domain.entity.CategoryBO;
import com.time.admin.domain.exception.AlreadyExistsException;
import com.time.admin.domain.redis.RedisUtil;
import com.time.admin.domain.service.AdminCategoryDomainService;
import com.time.admin.infra.basic.entity.Category;
import com.time.admin.infra.basic.service.CategoryService;
import com.time.admin.infra.basic.service.PostCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * 管理后台分类管理服务领域层实现类
 *
 * @author: HuangQi
 * @date: Created in 11:33 2025/10/9
 * @description: 管理后台分类管理服务领域层实现
 */
@Slf4j
@Service("adminCategoryService")
public class AdminCategoryDomainServiceImpl implements AdminCategoryDomainService {

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private PostCategoryService postCategoryService;

    @Autowired
    private RedisUtil redisUtil;

    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    private static final long CATEGORY_CACHE_TIMEOUT_MINUTES = 15L;
    private static final long CATEGORY_CACHE_JITTER_MINUTES = 5L;
    private static final TimeUnit CATEGORY_CACHE_TIMEUNIT = TimeUnit.MINUTES;

    @Override
    public Boolean add(CategoryBO categoryBO) {
        if (log.isInfoEnabled()) {
            log.info("AdminCategoryDomainServiceImpl.add.bo:{}", categoryBO);
        }

        // 参数转换
        Category category = CategoryBOConverter.INSTANCE.convertBOToEntity(categoryBO);
        category.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        // 检查当前分类的名称是否已经存在
        if (isExistCategory(category.getCategoryName())) {
            throw new AlreadyExistsException(ExceptionCode.CATEGORY_ALREADY_EXISTS, "该分类名称已经存在");
        }

        // 不存在这个分类就新增
        int count = categoryService.insert(category);

        // 返回结果
        return count > 0;
    }

    /**
     * 检查分类名称是否已经存在
     *
     * @param categoryName 分类名称
     * @return true存在，false不存在
     */
    private Boolean isExistCategory(String categoryName) {
        Category category = categoryService.queryByCategoryName(categoryName);
        return !Objects.isNull(category);
    }

    @Override
    public Boolean update(CategoryBO categoryBO) {
        if (log.isInfoEnabled()) {
            log.info("AdminCategoryDomainServiceImpl.update.bo:{}", categoryBO);
        }

        // 参数转换
        Category category = CategoryBOConverter.INSTANCE.convertBOToEntity(categoryBO);

        // 调用service
        int count = categoryService.update(category);

        // 返回结果
        return count > 0;
    }

    @Override
    public Boolean delete(Long id) {
        if (log.isInfoEnabled()) {
            log.info("AdminCategoryDomainServiceImpl.delete.id:{}", id);
        }

        // 参数转换
        Category category = new Category();
        category.setCategoryId(id);
        category.setIsDeleted(IsDeletedFlagEnum.DELETED.getCode());

        // 删除文章对应的分类的关联关系
        postCategoryService.deleteByCategoryId(id);

        // 删除这个分类的二级分类的父id
        categoryService.resetChildCategoryParentId(id);

        // 调用 service 删除分类
        int count = categoryService.update(category);

        // 返回结果
        return count > 0;
    }

    @Override
    @Transactional
    public Boolean batchDelete(List<Long> ids) {
        if (log.isInfoEnabled()) {
            log.info("AdminCategoryDomainServiceImpl.batchDelete.ids:{}", ids.toString());
        }

        // 遍历 ids 列表，删除每个分类对应的文章分类关联关系和二级分类的父id
        for (Long categoryId : ids) {
            // 删除文章对应的分类的关联关系
            postCategoryService.deleteByCategoryId(categoryId);
            // 删除这个分类的二级分类的父id
            categoryService.resetChildCategoryParentId(categoryId);
        }

        // 调用 service 删除分类
        int count = categoryService.batchDelete(ids, IsDeletedFlagEnum.DELETED.getCode());

        // 返回结果
        return count == ids.size();
    }

    @Override
    public List<CategoryBO> queryPrimaryCategory() {
        if (log.isInfoEnabled()) {
            log.info("AdminCategoryDomainServiceImpl.queryPrimaryCategory");
        }

        String cacheKey = redisUtil.buildKey("admin", "category", "primary");
        List<CategoryBO> cacheResult = getCache(cacheKey, new TypeReference<List<CategoryBO>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }

        // 调用service
        List<Category> categoryList = categoryService.queryPrimaryCategory();

        // 参数转换
        List<CategoryBO> categoryBOList = CategoryBOConverter.INSTANCE.convertEntityListToBO(categoryList);

        // 获取每个分类关联的文章数量
        categoryBOList.forEach(categoryBO -> {
            int postCount = postCategoryService.queryPostCountByCategoryId(categoryBO.getCategoryId());
            categoryBO.setPostCount(postCount);
        });

        setCache(cacheKey, categoryBOList);
        // 返回结果
        return categoryBOList;
    }

    @Override
    public List<CategoryBO> queryCategoryByPrimary(CategoryBO categoryBO) {
        if (log.isInfoEnabled()) {
            log.info("AdminCategoryDomainServiceImpl.queryCategoryByPrimary.bo :{}", categoryBO);
        }

        String cacheKey = redisUtil.buildKey("admin", "category", "children", serializeKey(categoryBO));
        List<CategoryBO> cacheResult = getCache(cacheKey, new TypeReference<List<CategoryBO>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }
        // 参数转换
        Category category = new Category();
        category.setParentId(categoryBO.getCategoryId());
        category.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        // 调用service
        List<Category> categoryList = categoryService.queryAllByCondition(category);

        // 参数转换
        List<CategoryBO> categoryBOList = CategoryBOConverter.INSTANCE.convertEntityListToBO(categoryList);

        // 获取每个分类关联的文章数量
        categoryBOList.forEach(catBO -> {
            int postCount = postCategoryService.queryPostCountByCategoryId(catBO.getCategoryId());
            catBO.setPostCount(postCount);
        });

        setCache(cacheKey, categoryBOList);
        // 返回结果
        return categoryBOList;
    }

    @Override
    public PageResult<CategoryBO> queryAllCategory(CategoryBO categoryBO) {
        if (log.isInfoEnabled()) {
            log.info("AdminCategoryDomainServiceImpl.queryAllCategory.bo :{}", categoryBO);
        }

        String cacheKey = redisUtil.buildKey("admin", "category", "queryAll", serializeKey(categoryBO));
        PageResult<CategoryBO> cacheResult = getCache(cacheKey, new TypeReference<PageResult<CategoryBO>>() {});
        if (cacheResult != null) {
            return cacheResult;
        }

        // 参数转换
        Category category = CategoryBOConverter.INSTANCE.convertBOToEntity(categoryBO);
        category.setIsDeleted(IsDeletedFlagEnum.UN_DELETED.getCode());

        PageResult<CategoryBO> pageResult = new PageResult<>();
        pageResult.setPageNo(categoryBO.getPageNo());
        pageResult.setPageSize(categoryBO.getPageSize());

        // 获取总记录数
        int total = categoryService.countAll();

        // 获取分页的分类信息
        int start = (pageResult.getPageNo() - 1) * pageResult.getPageSize();
        List<Category> categoryList = categoryService.queryPage(category, start, pageResult.getPageSize());

        // 参数转换
        List<CategoryBO> categoryBOList = CategoryBOConverter.INSTANCE.convertEntityListToBO(categoryList);
        // 获取每个分类关联的文章数量
        categoryBOList.forEach(item -> {
            int postCount = postCategoryService.queryPostCountByCategoryId(item.getCategoryId());
            item.setPostCount(postCount);
        });

        // 构建分页结果
        pageResult.setTotal(total);
        pageResult.setResult(categoryBOList);

        setCache(cacheKey, pageResult);
        // 返回结果
        return pageResult;
    }

    private <T> T getCache(String key, TypeReference<T> typeReference) {
        try {
            String cacheValue = redisUtil.get(key);
            if (cacheValue == null) {
                return null;
            }
            return OBJECT_MAPPER.readValue(cacheValue,
                    OBJECT_MAPPER.getTypeFactory().constructType(typeReference.getType()));
        } catch (Exception e) {
            log.warn("AdminCategoryDomainServiceImpl.getCache.error:key={}, msg={}", key, e.getMessage());
            return null;
        }
    }

    private void setCache(String key, Object value) {
        try {
            long ttl = CATEGORY_CACHE_TIMEOUT_MINUTES +
                    ThreadLocalRandom.current().nextLong(CATEGORY_CACHE_JITTER_MINUTES + 1);
            redisUtil.set(key, OBJECT_MAPPER.writeValueAsString(value), ttl, CATEGORY_CACHE_TIMEUNIT);
        } catch (Exception e) {
            log.warn("AdminCategoryDomainServiceImpl.setCache.error:key={}, msg={}", key, e.getMessage());
        }
    }

    private String serializeKey(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (Exception e) {
            log.warn("AdminCategoryDomainServiceImpl.serializeKey.error:{}", e.getMessage());
            return String.valueOf(obj);
        }
    }
}
